﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "ActionSetSelectedWallStyle.h"
#include "IUiDocument.h"
#include "IDocument.h"
#include "IUiView.h"
#include "IUserTransaction.h"
#include "IPickPointAction.h"
#include "Wall\Wall.h"
#include "IGraphicsNodeReference.h"
#include "IModelView.h"
#include "IGraphicsStyleManager.h"
#include "GraphicsNodeUtils.h"
#include "IPick.h"
#include "IPickCandidates.h"
#include "IPickFilter.h"
#include "IPickNodeReferenceAction.h"
#include "IPickTarget.h"
#include "ISelection.h"
#include "UiDocumentViewUtils.h"
#include "IGenericElement.h"
#include "IHighlights.h"
#include "IGraphicsNodeStyleAndMaterialOverride.h"
#include "IGraphicsStyle.h"
#include "Wall/WallStyleAndMaterialCustomizer.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 

using namespace Sample;
using namespace gcmp;

// 墙体拾取过滤器
class PickWallFilter :public gcmp::IPickFilter
{
public:
    virtual bool AllowElement(const gcmp::ElementId& id) const override
    {
        IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
        if (pDoc)
        {
            IElement* pElement = pDoc->GetElement(id);
            if (const IGenericElement* pGenericElement = quick_cast<const IGenericElement>(pElement))
            {
                if (const Wall* pWall = quick_cast<const Wall>(pGenericElement->GetExternalObject()))
                    return true;
            }
        }
        return false;
    };
    virtual bool AllowGraphicsNode(const gcmp::IGraphicsNodeReference& nodeReference) const override { return true; };
    virtual bool SetPickTargetOption(gcmp::IPickTarget* pickTarget) override
    {
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pickTarget, L"pickTarget为空", L"GDMP", L"2023-09-30");
        pickTarget->EnableGraphicsElementShape();
        return true;
    }
};

ActionSetSelectedWallStyle::ActionSetSelectedWallStyle()
    : m_isUserCancelled(false)
{
}

ActionSetSelectedWallStyle::~ActionSetSelectedWallStyle()
{

}

void ActionSetSelectedWallStyle::OnChildActionFinished(IUiView* pCurrentView, const ActionOutput& childActionReturnParam)
{
    gcmp::IDocument * pDoc = GetDoc();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"文档为空", L"GDMP", L"2023-09-30");

    if (m_isUserCancelled || m_gNodeReferencesSelection.empty())
    {
        ISelection::Get()->Clear(pDoc);
        IHighlights::Get()->Clear();
        m_bActionStart = false;

        CleanupTempGraphicsShape();
        MarkFinishStatus(ActionFinishStatus::Cancelled);
        UpdateView();
        return;
    }
    std::vector<ElementId> ids;
    FOR_EACH(item, m_gNodeReferencesSelection)
    {
        ElementId elemId = item->GetElementId();
        ids.emplace_back(elemId);
    }
    SetWallStyle(pCurrentView, ids);
    SelectWalls(pCurrentView);
    UpdateView();
}

void ActionSetSelectedWallStyle::SelectWalls(gcmp::IUiView* pCurrentView)
{
    bool bSingleSelectModeInput = false;
    PickNodeReferenceExchangeData exchangeData(bSingleSelectModeInput, &m_gNodeReferencesSelection, &m_isUserCancelled, &m_currentMousePt);

    PickNodeReferenceOption pickOptions;
    pickOptions.SetPickPixelTolerance(10);
    pickOptions.SetMultiSelect(true);
    pickOptions.SetMouseTooltipMessage(L"选择墙体");
    pickOptions.SetFinishedMode(ActionFinishedMode::LButtonDown);
    pickOptions.SetIsPickingHighlightOnlyGraphicsNodeAllowed(true);

    OwnerPtr<IPickFilter> opPickFilter = NEW_AS_OWNER_PTR(PickWallFilter);
    DBG_WARN_AND_RETURN_VOID_UNLESS(opPickFilter, L"创建墙体拾取过滤器失败", L"GDMP", L"2023-09-30");

    gcmp::OwnerPtr<IAction> opPickNodeReferenceAction = IPickNodeReferenceAction::Create(exchangeData,
        TransferOwnership(opPickFilter), pickOptions);
    DBG_WARN_AND_RETURN_VOID_UNLESS(opPickNodeReferenceAction, L"创建拾取墙体Action失败", L"GDMP", L"2023-09-30");
    {
        ActionBase *pActionBase = dynamic_cast<ActionBase*>(opPickNodeReferenceAction.get());
        pActionBase->SetCursorType(CursorType::CrossHairCursor);
    }

    StartChildAction(TransferOwnership(opPickNodeReferenceAction));
}

void ActionSetSelectedWallStyle::InitAction(gcmp::IUiView* pCurrentView)
{
    const GraphicsNodeReferenceOwnerPtrSet& selectedElems = ISelection::Get()->GetGraphicsNodeReferences();
    if (!selectedElems.empty())
    {
        std::vector<ElementId> ids;
        FOR_EACH(item, selectedElems)
        {
            ElementId elemId = item->GetElementId();
            ids.emplace_back(elemId);
        }
        SetWallStyleEx(pCurrentView, ids);
        MarkFinishStatus(ActionFinishStatus::Successful);
        return;
    }
    m_bActionStart = true;
    SelectWalls(pCurrentView);
}

void ActionSetSelectedWallStyle::SetWallStyle(gcmp::IUiView* pCurrentView, const std::vector<gcmp::ElementId>& ids)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView != nullptr, L"视图为空", L"GDMP", L"2023-09-30");
    IModelView *pModelView = pCurrentView->GetModelView();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pModelView != nullptr, L"视图为空", L"GDMP", L"2023-09-30");
    IDocument *pDoc = pModelView->GetDocument();
    if (ids.empty())
        return;

    OwnerPtr<IUserTransaction> opUt = IUserTransaction::Create(pDoc, GBMP_TR(L"修改所选墙体样式"), true);
    DBG_WARN_AND_RETURN_VOID_UNLESS(opUt, L"ut为空", L"GDMP", L"2023-09-30");

    IModelView* pModeView = UiDocumentViewUtils::GetCurrentModelView();
    FOR_EACH(elemId, ids)
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(elemId.IsValid(), L"elemId无效", L"GDMP", L"2023-09-30");
        IElement* pElement = pDoc->GetElement(elemId);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"pElement为空", L"GDMP", L"2023-09-30");

        IGraphicsNodeStyleAndMaterialOverride* pStyleAndMaterialOverride =
            pElement->GetShapeGraphicsNodeStyleAndMaterialOverrideComponentFW();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pStyleAndMaterialOverride, L"pStyleAndMaterialOverride为空", L"GDMP", L"2023-09-30");

        ElementId styleId = pStyleAndMaterialOverride->GetOverriddenGraphicsStyle();
        if (styleId.IsValid())
        {
            IGraphicsStyle* opStyle = quick_cast<IGraphicsStyle>(pDoc->GetElement(styleId));
            DBG_WARN_AND_RETURN_VOID_UNLESS(opStyle, L"opStyle为空", L"GDMP", L"2023-09-30");
            OwnerPtr<IGraphicsStyleData> opStyleData = opStyle->GetGraphicsStyleData();
            opStyleData->SetColor(Color::Red);
            opStyleData->SetProjectionLineColor(Color::Red);
            opStyleData->SetSectionLineColor(Color::Red);

            opStyle->SetGraphicsStyleData(*opStyleData);
        }
        else
        {
            IGraphicsStyle* pStyle = IGraphicsStyle::Create(pDoc, ElementCreationOptions::Normal);
            DBG_WARN_AND_RETURN_VOID_UNLESS(pStyle, L"pGstyle为空", L"GDMP", L"2023-09-30");
            OwnerPtr<IGraphicsStyleData> opStyleData = IGraphicsStyleData::Create();
            DBG_WARN_AND_RETURN_VOID_UNLESS(opStyleData, L"opStyleData为空", L"GDMP", L"2023-09-30");
            opStyleData->SetColor(Color::Red);
            opStyleData->SetProjectionLineColor(Color::Red);
            opStyleData->SetSectionLineColor(Color::Red);

            pStyle->SetGraphicsStyleData(*opStyleData);
            styleId = pStyle->GetElementId();
        }
#if 0
        //这种方式修改的是当前视图中的样式
        pModeView->OverrideGraphicsStyleByElementId(elemId, styleId);
#else
        //这种方式修改Element的样式
        pStyleAndMaterialOverride->SetGraphicsNodeStyleAndMaterialCustomizer(nullptr);
        pStyleAndMaterialOverride->OverrideGraphicsStyle(styleId);
#endif
    }
    opUt->Commit();
    ISelection::Get()->Clear(pDoc);
    IHighlights::Get()->Clear();
}


void ActionSetSelectedWallStyle::SetWallStyleEx(gcmp::IUiView* pCurrentView, const std::vector<gcmp::ElementId>& ids)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCurrentView != nullptr, L"视图为空", L"GDMP", L"2023-09-30");
    IModelView *pModelView = pCurrentView->GetModelView();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pModelView != nullptr, L"视图为空", L"GDMP", L"2023-09-30");
    IDocument *pDoc = pModelView->GetDocument();
    if (ids.empty())
        return;

    OwnerPtr<IUserTransaction> opUt = IUserTransaction::Create(pDoc, GBMP_TR(L"修改所选墙体样式"), true);
    DBG_WARN_AND_RETURN_VOID_UNLESS(opUt, L"ut为空", L"GDMP", L"2023-09-30");

    IGraphicsStyle* pGraphicsStyle = IGraphicsStyle::Create(pDoc, gcmp::ElementCreationOptions::Normal);
    OwnerPtr<IGraphicsStyleData> opGraphicsStyleData = IGraphicsStyleData::Create();
    opGraphicsStyleData->SetColor(Color::Black);
    opGraphicsStyleData->SetTransparency(0.3);
    pGraphicsStyle->SetGraphicsStyleData(*opGraphicsStyleData);

    IModelView* pModeView = UiDocumentViewUtils::GetCurrentModelView();
    FOR_EACH(item, ids)
    {
        ElementId elemId = item;
        DBG_WARN_AND_RETURN_VOID_UNLESS(elemId.IsValid(), L"elemId无效", L"GDMP", L"2023-09-30");
        IElement* pElement = pDoc->GetElement(elemId);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"pElement为空", L"GDMP", L"2023-09-30");

        if (IGraphicsNodeStyleAndMaterialOverride* pOverride = pElement->GetShapeGraphicsNodeStyleAndMaterialOverrideComponentFW())
        {
            OwnerPtr<WallStyleAndMaterialCustomizer> opCustomizer = NEW_AS_OWNER_PTR(WallStyleAndMaterialCustomizer, pElement);
            DBG_WARN_AND_RETURN_VOID_UNLESS(opCustomizer, L"opCustomizer指针为空", L"GDMP", L"2023-09-30");
            opCustomizer->SetGraphicsStyleId(pGraphicsStyle->GetElementId());
            pOverride->SetGraphicsNodeStyleAndMaterialCustomizer(TransferOwnership(opCustomizer));
        }
    }
    opUt->Commit();
    ISelection::Get()->Clear(pDoc);
    IHighlights::Get()->Clear();
}

